#!/usr/bin/env python

import pygame,sys,time
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *

global width
global height


def remap(x,a,b,c,d):
    return c + float(d - c) * (float(x - a)/float(b - a))

def draw_lines(lst):
    glBegin(GL_LINES)
    for pair in lst:
        glVertex(*pair[0])
        glVertex(*pair[1])
    glEnd()

class ToolBase:
    def __init__(self):
        self.ldown = False
        self.rdown = False
        pass
    def pass_message(self,event):
        global width
        global height
        if event.type == MOUSEBUTTONDOWN:
            xp,yp = event.pos
            x = remap(xp,0,width,-1,1)
            y = remap(yp,height,0,-1,1)
            if event.button == 1:
                self.ldown = True
                self.leftDown( (x,y) )
            elif event.button == 3:
                self.rdown = True
                self.rightDown( (x,y) )
        elif event.type == MOUSEBUTTONUP:
            xp,yp = event.pos
            x = remap(xp,0,width,-1,1)
            y = remap(yp,height,0,-1,1)
            if event.button == 1:
                self.ldown = False
                self.leftUp( (x,y) )
            elif event.button == 3:
                self.rdown = False
                self.rightUp( (x,y) )
        elif event.type == MOUSEMOTION:
            xp,yp = event.pos
            x = remap(xp,0,width,-1,1)
            y = remap(yp,height,0,-1,1)
            self.moveMouse((x,y))

            
    def draw_current(self):
        pass
    def moveMouse(self,pos):
        pass
    def leftDown(self,pos):
        pass
    def leftUp(self,pos):
        pass
    def rightDown(self,pos):
        pass
    def rightUp(self,pos):
        pass
    def get_model(self):
        pass
    def reset(self):
        pass

class LineSegmentTool(ToolBase):
    def __init__(self):
        ToolBase.__init__(self)
        self.lines = []
        self.start = (0.0,0.0)
        self.end = (0.0,0.0)
    def draw_current(self):
        if self.ldown:
            draw_lines([(self.start,self.end)])
        draw_lines(self.lines)
    def moveMouse(self,pos):
        if self.ldown:
            self.end = pos
        else:
            self.start = pos
    def leftDown(self,pos):
        self.start = pos
        self.end = pos
        pass
    def leftUp(self,pos):
        self.lines.append( (self.start,self.end) )
        pass
    def rightDown(self,pos):
        pass
    def rightUp(self,pos):
        pass
    def get_model(self):
        return self.lines
    def reset(self):
        pass

class ClosedLoopTool(ToolBase):
    def __init__(self):
        ToolBase.__init__(self)
        self.active = False
        self.enabled = True
        self.lines = []
        self.cur = (0.0,0.0)
    def draw_current(self):
        if self.active:
            pass
        else:
            pass
            
    def moveMouse(self,pos):
        self.cur = pos
    def leftDown(self,pos):
        self.active = True
        pass
    def leftUp(self,pos):
        pass
    def rightDown(self,pos):
        pass
    def rightUp(self,pos):
        pass
    def get_model(self):
        return self.lines
    def reset(self):
        pass

class OpenLoopTool(ToolBase):
    def __init__(self):
        ToolBase.__init__(self)
        self.lines = []
        self.start = (0.0,0.0)
        self.end = (0.0,0.0)
    def draw_current(self):
        pass
    def moveMouse(self,pos):
        pass
    def leftDown(self,pos):
        pass
    def leftUp(self,pos):
        pass
    def rightDown(self,pos):
        pass
    def rightUp(self,pos):
        pass
    def get_model(self):
        return self.lines
    def reset(self):
        pass

class SquareLoopTool(ToolBase):
    def __init__(self):
        ToolBase.__init__(self)
        self.lines = []
        self.start = (0.0,0.0)
        self.end = (0.0,0.0)
    def draw_current(self):
        pass
    def moveMouse(self,pos):
        pass
    def leftDown(self,pos):
        pass
    def leftUp(self,pos):
        pass
    def rightDown(self,pos):
        pass
    def rightUp(self,pos):
        pass
    def get_model(self):
        return self.lines
    def reset(self):
        pass
    pass

def make_texture(fname):
    rawtex = pygame.image.load(fname)
    texdat = pygame.image.tostring(rawtex,"RGBA",1)
    tex = glGenTextures(1)
    glBindTexture(GL_TEXTURE_2D,tex)
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR)
    glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,64,64,0,GL_RGBA,GL_UNSIGNED_BYTE,texdat)
    return tex

def draw_textured_quad(texture,left,top,width,height):
    glBindTexture(GL_TEXTURE_2D,texture)
    glBegin(GL_QUADS)
    glTexCoord2f(0,0);  glVertex(left       ,top         )
    glTexCoord2f(1,0);  glVertex(left       ,top - height)
    glTexCoord2f(1,1);  glVertex(left+width ,top - height)
    glTexCoord2f(0,1);  glVertex(left+width ,top         )
    glEnd()

draw_textured_square = lambda tex,left,top,size : draw_textured_quad(tex,left,top,size,size)
    

def main():
    global width
    global height
    pygame.init()
    
    size = width,height = 640,640
    screen = pygame.display.set_mode(size,pygame.OPENGL | pygame.DOUBLEBUF)
    
    glLoadIdentity()
    glMatrixMode(GL_PROJECTION)
    gluOrtho2D(-1,1,-1,1)
    glMatrixMode(GL_MODELVIEW)
    
    glClearColor(0,0,0,0)
    
    running = True
    
    x,y = 0,0
    
    obj_lists = []

    draw_buttons = False

    button1_tex = make_texture('line_segments.png')
    button2_tex = make_texture('closed_loop.png')
    button3_tex = make_texture('open_loop.png')
    button4_tex = make_texture('square_loop.png')

    
    def draw_UI():
        bs = 0.2
        glPushMatrix()
        glEnable(GL_TEXTURE_2D)
        glColor(1,1,1,1)


        off = 1
        glPushName(off)
        draw_textured_square(button1_tex,-1,1-bs*off,bs)
        glPopName()

        off = 2
        glPushName(off)
        draw_textured_square(button2_tex,-1,1-bs*off,bs)
        glPopName()

        off = 3
        glPushName(off)
        draw_textured_square(button3_tex,-1,1-bs*off,bs)
        glPopName()

        off = 4
        glPushName(off)
        draw_textured_square(button4_tex,-1,1-bs*off,bs)
        glPopName()

        glDisable(GL_TEXTURE_2D)
        glPopMatrix()


    cur_tool = None

    def render():
        if draw_buttons:
            draw_UI()
        if cur_tool:
            cur_tool.draw_current()
        for lst in obj_lists:
            draw_lines(lst)

    while running:
        handled = False
        for event in pygame.event.get():
            if event.type == QUIT:
                running = False
            elif event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    running = False
                if event.key == K_LSHIFT:
                    draw_buttons = True
            elif event.type == KEYUP:
                if event.key == K_LSHIFT:
                    draw_buttons = False
            
            elif event.type == MOUSEBUTTONUP:
                xp,yp =  event.pos
                if draw_buttons:
                    sbuf = glSelectWithCallback(xp,yp,render,1,1)
                    hits = [x for x in sbuf]
                    print hits
                    if hits:
                        if cur_tool:
                            obj_lists.append(cur_tool.get_model())
                        draw_buttons = False
                        t = hits[0][2][0]
                        if t == 1:
                            cur_tool = LineSegmentTool()
                        elif t == 2:
                            cur_tool = ClosedLoopTool()
                        elif t == 3:
                            cur_tool = OpenLoopTool()
                        elif t == 4:
                            cur_tool = SquareLoopTool()
                        else:
                            draw_buttons = True
                    handled = True  
                    #use hits[0][2] to detemine which tool we use

            elif event.type == MOUSEMOTION:
                xp,yp =  event.pos
                x = remap(xp,0,width,-1,1)
                y = remap(yp,height,0,-1,1)
            if cur_tool and not draw_buttons and not handled:
                cur_tool.pass_message(event)
        
        glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT)
        glColor(1,1,1,1)

        render()

        glFlush()
        pygame.display.flip()
    
    pygame.quit()

if __name__=='__main__':
    main()
